import 'dart:io';
import 'dart:core';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:freedom/entity/restful.dart';
import 'package:freedom/page/mahjong/common/message_content.dart';
import 'package:freedom/util/api_router.dart';
import 'package:freedom/util/http.dart';
import 'package:freedom/util/socket_server.dart';
import 'package:freedom/webrtc/user_peer_connnection.dart';
import 'package:synchronized/synchronized.dart';

/// webrtc 总体流程
/// 1.本地打开媒体
/// 2.本地打开socket发送消息到服务器 进入房间 记录用户房间号
/// 3.当第二个人加入的时候 发送消息 给webrtc 我进来了
/// 4.当收到第二个人进来过后创建 offer 将本地的offer 发送到服务器转发

class MircoPhoneOpen {
  static MircoPhoneOpen? _instance;

  bool openMirco = false;

  final Map<int, UserPeerConnection> _diskAllUserPc = {};

  static final Lock _lock = Lock();

  final RTCVideoRenderer _localRenderer = RTCVideoRenderer();

  MircoPhoneOpen._();

  factory MircoPhoneOpen() {
    _instance ??= MircoPhoneOpen._();
    return _instance!;
  }

  MediaStream? _localMediaStream;

  static MediaStream? get localMediaStream =>
      MircoPhoneOpen()._localMediaStream;

  // 处理某个用户的webrtc请求
  void doUserAction(int fromUid, String? cmd, dynamic msg) {
    UserPeerConnection? peerConnection = _diskAllUserPc[fromUid];
    _lock.synchronized(() {
      // 本地创建  peerConnection
      if (peerConnection == null) {
        peerConnection =
            UserPeerConnection(fromUid, _localMediaStream, openMirco);
        _diskAllUserPc[fromUid] = peerConnection!;
      }
      return peerConnection!;
    }).then((pcc) {
      switch (cmd) {
        case "conn":
          // 有人主动和我发起连接,我把offer发送给这个人
          pcc.doOffer();
          break;
        case "offer":
          pcc.remoteOffer(msg);
          break;
        case "answer":
          pcc.remoteAnswer(msg);
          break;
        case "candidate":
          pcc.remoteCandidate(msg);
          break;
        case "logout":
          pcc.logout();
          _diskAllUserPc.remove(fromUid);
          break;
        default:
      }
    });
  }

  //初始化 连接  web rtc

  void init() async {
    SocketServer().messageSteam.listen((data) {
      // 当收到有人加入进来过后  创建与对端的 pc
      var serverMessage = MessageContent.fromJson(json.decode(data));
      if (serverMessage.type != MessageContent.MT_VOICE) {
        return;
      }
      VoiceMessage voiceMessage = VoiceMessage.fromJson(serverMessage.body);
      for (var userId in voiceMessage.correlationUIds) {
        doUserAction(userId, voiceMessage.cmd, voiceMessage.msg);
      }
    });
    await _localRenderer.initialize();
    /* if (!WebRTC.initialized) {
      await WebRTC.initialize();
    } */
    closeLocalMirco();
    for (var element in _diskAllUserPc.entries) {
      element.value.pc?.dispose();
    }
    _diskAllUserPc.clear();
  }

  // 游戏中开启麦克风
  void openLocalMirco() async {
    try {
      openMirco = true;
      final mediaConstraints = <String, dynamic>{
        'audio': {
          'echoCancellation': true,
          'autoGainControl': true,
          'googNoiseSuppression': true,
          'googHighpassFilter': true,
          'noiseSuppression': true,
        },
        'video': false
      };
      await navigator.mediaDevices
          .getUserMedia(mediaConstraints)
          .then((result) {
        _localMediaStream = result;
        _localRenderer.srcObject = _localMediaStream;
        for (var element in _diskAllUserPc.entries) {
          element.value.resetState(_localMediaStream);
        }
        // 向服务器发送有新人加入进来
        var data = MessageContent<Map>(
            type: MessageContent.MT_VOICE, body: {'cmd': "conn"}).toJson();
        Http.getInstance().request<Restful>(ApiRouter.roomMessage,
            contentType: ContentType.json,
            type: RequestEnum.POST,
            showErrorMsg: true,
            data: data,
            success: (data) {});
      });

      // stopRecording();
      // 向服务器发送我加入进来了 服务器收到后发送给其它人 不包含自己
    } catch (e) {
      if (kDebugMode) {
        print('Failed to start recording: $e');
      }
    }
  }

  // 游戏中关闭麦克风
  void closeLocalMirco() async {
    for (var element in _diskAllUserPc.entries) {
      element.value.clearTrack();
      element.value.localMediaStream = null;
    }
    // 清理掉本地的 流对象  关闭
    _localMediaStream?.getAudioTracks().forEach((track) {
      track.enabled = false;
    });
    _localMediaStream?.dispose();
    _localRenderer.srcObject = null;
    _localMediaStream = null;
  }

  //完全退出
  void exitVoiceRoom() async {
    for (var element in _diskAllUserPc.entries) {
      element.value.logout();
    }
    _diskAllUserPc.clear();
    // 清理掉本地的 流对象  关闭
    _localMediaStream?.getAudioTracks().forEach((track) {
      track.enabled = false;
      track.stop();
    });
    _localMediaStream?.dispose();
    _localRenderer.srcObject?.dispose();
    _localMediaStream = null;
  }
}
